//
// Created by Axe on 2023/12/21.
//

#include "axedata_jni.h"
#include "../util/log.h"
#include <stdlib.h>
#include "axedata.h"

#define CLASS_NAME "com/axe/jnistudy/AxeData"

static jclass axeDataClass = nullptr;
static jmethodID getTestBeanJniMethod = nullptr;
static JNIEnv *javaEnv = nullptr;

jobject getAxeDataInstance() {
    if (axeDataClass == nullptr) {
        LOGI("enter getAxeDataInstance failed, caused by class is nullptr");
        return nullptr;
    }
    jmethodID getInstanceId = javaEnv->GetStaticMethodID(axeDataClass,"getInstance","()Lcom/axe/jnistudy/AxeData;");
    if (getInstanceId == nullptr) {
        LOGI("enter getAxeDataInstance failed, caused by getInstanceId is nullptr");
        return nullptr;
    }
    jobject jobj = javaEnv->CallStaticObjectMethod(axeDataClass, getInstanceId);
    if (jobj == nullptr) {
        LOGI("enter getAxeDataInstance failed, caused by jobj is nullptr");
        return nullptr;
    }
    return jobj;
}



axedata getAxeData() {

    JNIEnv *env = javaEnv;

    jobject jobj = getAxeDataInstance();
    if (jobj == nullptr) {
        LOGI("enter startTest jobj is null");
    } else {
        LOGI("enter startTest jobj is not null");
    }

    jobject testBeanJobj = javaEnv->CallObjectMethod(jobj,getTestBeanJniMethod);
    if (testBeanJobj == nullptr) {
        LOGI("enter startTest testBeanJobj is null");
    } else {
        LOGI("enter startTest testBeanJobj is not null");
    }

    jclass testBeanClass = reinterpret_cast<jclass>(env->NewGlobalRef(env->FindClass("com/axe/jnistudy/TestBean")));

    // 开始解析testBeanJobj

    // 解析name
    jfieldID field_name = env->GetFieldID(testBeanClass, "name", "Ljava/lang/String;");
    jstring jname = (jstring)env->GetObjectField(testBeanJobj, field_name);
    const char * c_javaName = env->GetStringUTFChars(jname , NULL);
    LOGI("enter startTest get jname: %s",c_javaName);

    // 解析des
    jfieldID field_des = env->GetFieldID(testBeanClass, "des", "Ljava/lang/String;");
    jstring jdes = (jstring)env->GetObjectField(testBeanJobj, field_des);
    const char * c_des = env->GetStringUTFChars(jdes , NULL);
    LOGI("enter startTest get jdes: %s",c_des);

    // 解析age
    jfieldID field_age = env->GetFieldID(testBeanClass, "age", "I");
    jint jage = env->GetIntField(testBeanJobj, field_age);
    LOGI("enter startTest get jage:%d", jage);

    axedata axedata(c_javaName, c_des, jage);
    LOGI("axeData get axeData name:%s ,des %s, age:%d",axedata.getName().c_str(), axedata.getDes().c_str(), axedata.getAge());

    env->ReleaseStringUTFChars(jname, c_javaName);
    env->ReleaseStringUTFChars(jdes, c_des);

    return axedata;
}


/**
 * 动态注册对应的方法
 */
extern "C" JNIEXPORT void JNICALL startTest(JNIEnv *env, jclass thiz) {
    LOGI("enter startTest");
    axedata axedata = getAxeData();
    LOGI("axeData2 get axeData2 name:%s ,des %s, age:%d",axedata.getName().c_str(), axedata.getDes().c_str(), axedata.getAge());

}

/**
 * 动态注册的方法
 */
static JNINativeMethod methods[] = {
        {"natveStartTest", "()V", (void *) startTest}
};

/**
 * 获取java层native方法的 methodID
 * @param clazz jclass
 * @param env  jniEnv
 * @return true
 */
bool registerJavaMethodID(jclass clazz, JNIEnv *env) {
    getTestBeanJniMethod = env->GetMethodID(clazz, "getTestBean", "()Lcom/axe/jnistudy/TestBean;");
    if (getTestBeanJniMethod == NULL) {
        LOGE(TAG, "GetMethodID getTestBean failed");
        return false;
    }
    return true;
}

bool loadAxeDataJNI(JavaVM *vm, JNIEnv *env) {
    LOGI("enter loadFileIsolationJNI");
    if (!vm || !env) {
        return false;
    }

    javaEnv = env;

    // 获取class对象
    axeDataClass = reinterpret_cast<jclass>(env->NewGlobalRef(env->FindClass(CLASS_NAME)));
    if (axeDataClass == nullptr) {
        LOGE("enter loadAxeDataJNI failed, caused by %s is null", CLASS_NAME);
        return false;
    }

    // 动态注册native方法
    if (env->RegisterNatives(axeDataClass, methods, sizeof(methods) / sizeof(methods[0])) < 0) {
        LOGE("enter loadAxeDataJNI failed, RegisterNatives failed");
        return false;
    }

    if (!registerJavaMethodID(axeDataClass, env)) {
        LOGE("enter loadAxeDataJNI failed, registerJavaMethodID failed");
        return false;
    }

    LOGI("loadAxeDataJNI success");
    return true;
}